using System;
using System.Collections;
using System.Html;
using System.Runtime.CompilerServices;
using Awaiter;
using jQueryApi;

namespace Nsb.Classes
{
    [IgnoreNamespace]
    public class EditHtml : Actor
    {
        protected readonly Await EAwp;
        private readonly Dictionary _eCss;
        protected readonly jQueryObject EdEl;
        protected readonly string TextIn;
        protected readonly jQueryObject Textarea;

        private static jQueryObject _autoErDiv;
        private jQueryObject _autoEr;
        private static readonly RegularExpression RegExLf = new RegularExpression(@"\r?\n", "g");

        public EditHtml(Await awp, jQueryObject edEl)
        {
            EAwp = awp;
            EdEl = edEl;

            Element = jQuery.FromHtml("<div class='EditContent'/>")
                .AppendTo(Document.Body)
                .Bind("keydown.esc", delegate(jQueryEvent e) { Keys.EscKey(e, Cancel); })
                ;

            TextIn = edEl.Plugin<Jewl>().GetFValueString();
            Textarea = jQuery.FromHtml("<textarea/>")
                .AppendTo(Element)
                .Plugin<Jewl>().FValueString(TextIn)
                .Blur(Ok)
                ;

            _eCss = edEl.Plugin<Jewl>().CloneEditCSS();

            Textarea
                .CSS(_eCss)
                .Bind("keyup.EditHtml",
                      delegate(jQueryEvent e)
                      {
                          if (Keys.BlackKey(e) || (e.Which == 13 && e.ShiftKey))
                              Textarea.CSS("height", AutoHeight(Textarea) + "px");
                      })
                .Bind("keydown.EditHtml",
                      delegate(jQueryEvent e)
                      {
                          if (e.Which == 9)
                              Next(e);
                          else if (e.Which == 13)
                          {
                              if (e.ShiftKey)
                                  return;
                              CancelEvent(e);
                              Textarea.Blur();
                              Cont(e);
                          }
                          else if (e.Which == 40)
                          {
                              Window.SetTimeout(delegate { if ((int)Textarea.Plugin<Jewl>().GetSelection()["start"] == Textarea.GetValue().Length) Next(e); }, 1);
                          }
                          else if (e.Which == 38)
                          {
                              int sel = (int)Textarea.Plugin<Jewl>().GetSelection()["start"];
                              Window.SetTimeout(delegate { if ((int)Textarea.Plugin<Jewl>().GetSelection()["start"] == sel) Prior(e); }, 1);
                          }
                      })
                ;

            Keys.FilterAll(Element);

            new Await().AddDx(delegate { Textarea.Focus(); }).Commit();
        }

        public virtual void Destroy()
        {
            Element.Remove();
        }

        protected virtual void Ok(jQueryEvent e)
        {
            string txtOut = Textarea.Plugin<Jewl>().GetFValueString();
            EAwp["changed"] = TextIn != txtOut;
            EdEl.Plugin<Jewl>().FValueString(txtOut);
            Destroy();
            EAwp.Done();
        }

        protected virtual void Cancel(jQueryEvent e)
        {
            Destroy();
            throw new Exception(Exceptions.UserCancelled);
        }

        /// <summary>
        /// What to do when shift-enter is pressed to signify edit is done
        /// and move on to possibly create a new list item.
        /// </summary>
        /// <param name="e">jQueryEvent</param>
        protected virtual void Cont(jQueryEvent e)
        {
        }

        protected virtual void Next(jQueryEvent e)
        {
        }

        protected virtual void Prior(jQueryEvent e)
        {
        }

        private int AutoHeight(jQueryObject el)
        {
            if (_autoEr == null)
            {
                if (_autoErDiv == null)
                    _autoErDiv = jQuery.FromHtml("<div style='position:absolute;visibility:hidden'/>").AppendTo(Document.Body);
                _autoEr = jQuery.FromHtml("<div/>").CSS(_eCss).PrependTo(_autoErDiv);
                _autoEr.CSS(
                    new Dictionary(
                        "top", 0,
                        "height", "auto",
                        "position", "relative",
                        "overflow", "visible"
                        )
                    );
            }
            _autoEr.Html(el.GetValue().ReplaceRegex(RegExLf, "<br>"));
            return _autoEr.GetHeight();
        }


    }
}
